<template>
  <el-container id="app">
    <el-header id="appTopHeader">
      <div id="appLogo">
        <img src="./assets/image/logo.png" alt="">
      </div>
      <el-menu id="topNavMenu" :default-active="topMenuActiveIndex" class="el-menu-demo" mode="horizontal" @select="handleTopMenuSelect" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
        <el-menu-item index="0">菜单一</el-menu-item>
        <el-submenu index="2">
          <template slot="title">菜单二</template>
          <el-menu-item index="2-0">选项1</el-menu-item>
          <el-menu-item index="2-2">选项2</el-menu-item>
          <el-submenu index="2-3">
            <template slot="title">选项4</template>
            <el-menu-item index="2-3-0">选项1</el-menu-item>
            <el-menu-item index="2-3-2">选项2</el-menu-item>
          </el-submenu>
        </el-submenu>
      </el-menu>
    </el-header>
    <el-container>
      <el-aside width="200px" id="leftNavMenu">
        <!-- vue中要递归生成菜单，要用主文件引用子组件，子组件去递归才能实现。单单一个页面是无法递归的 -->
        <Menu :menuList="treeFormatLeftMenu" :activeMenuId="leftMenuActiveIndex" @select="handleLeftMenuSelect"></Menu>
      </el-aside>
      <el-main id="centerDiv">
        <!-- 面包屑 -->
        <el-breadcrumb separator="/" id="centerBreadcrumb">
          <el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="index">{{item.name}}</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 页面tabList -->
        <el-tabs v-model="activeTabId" type="border-card" id="centerTab" closable @tab-remove="handleRemoveTab" @tab-click="handleClickTab">
          <el-tab-pane v-for="(menu, index) in tabList" :key="menu.id + index" :label="menu.name" :name="menu.id"></el-tab-pane>
          <!-- 路由出口 -->
          <!-- 这种写法，重新打开后切换下tab，缓存又回来了，因为没有删除keepAlive底层的缓存 -->
          <!-- <keep-alive>
            <router-view v-if='$route.meta.keepAlive'></router-view>
          </keep-alive>
          <router-view v-if='!$route.meta.keepAlive' /> -->

          <!-- 更新include属性的时候，keepAlive也会维护底层的缓存，即如果删除keepAliveComponennt的元素，会对应删除该key对应的缓存 -->
          <keep-alive :include="keepAliveComponennt">
            <router-view />
          </keep-alive>
        </el-tabs>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
import '@/assets/style/reset.css'

import Menu from './components/Menu';
import leftMenu from './api/leftMenu.json';

export default {
  components: {
    Menu,
  },
  data () {
    return {
      // 上方菜单选中的index
      topMenuActiveIndex: '',
      // 左侧菜单数据（扁平化）
      leftMenu: leftMenu,
      // 左边菜单选中的index
      leftMenuActiveIndex: '0',
      // tabList
      tabList: [
        { id: '0', name: '主页', routerPath: '/' }
      ],
      keepAliveComponennt: [],
      // 被选中的tab选项卡
      activeTabId: '0', //0为主页，默认选中主页
      // 导航面包屑
      breadcrumbList: []
    };
  },
  computed: {
    // 将扁平化的菜单数据 格式化成 树状的格式
    treeFormatLeftMenu () {
      let menuList = [];
      // 递归获取菜单下的菜单
      let getMenuListByParentId = (parentMenu) => {
        let subMenuList = this.leftMenu.filter(item => item.parentId == parentMenu.id);
        parentMenu.children = subMenuList;
        parentMenu.children.forEach(item => {
          // 如果当前菜单为文件夹类型，则获取子菜单
          if (item.isFolder) {
            getMenuListByParentId(item)
          }
        })
      }
      // 获取所有的根菜单
      let rootMenuList = this.leftMenu.filter(item => item.parentId == -1);
      rootMenuList.forEach(item => {
        // 如果当前菜单为文件夹类型，则获取子菜单
        if (item.isFolder) {
          getMenuListByParentId(item)
        }
        menuList.push(item);
      })
      return menuList;
    }
  },
  methods: {
    //  根据path进行路由
    routeByPath (path) {
      // vue2.0中的$router 和 $route的区别 https://www.cnblogs.com/czy960731/p/9288830.html
      if (this.$route.path != path) {
        this.$router.replace({ path: path });
      }
    },
    // 根据命名进行路由
    routeByName (name) {
      if (this.$route.name != name) {
        this.$router.replace({ name: name });
      }
    },
    getRouterNameByMenuItem (menuItem) {
      if (menuItem.routerName) {
        return menuItem.routerName;
      }
      for (let route of this.$router.options.routes) {
        if (route.path == menuItem.routerPath) {
          return route.name;
        }
      }
      return undefined;
    },
    /**
     * 处理顶部导航栏菜单item选中事件
     * @param key 被点击菜单的id
     * @param keyPath 被点击菜单的面包屑路径
     */
    handleTopMenuSelect (key, keyPath) {
      console.log(key, keyPath);
    },
    // 处理左侧导航栏菜单item选中事件
    handleLeftMenuSelect (key, keyPath) {
      // 被点击的菜单
      let menu = this.leftMenu.find(item => item.id == key);
      menu.keyPath = keyPath; // 面包屑
      menu.routerName = this.getRouterNameByMenuItem(menu)
      // 跳转路由
      this.routeByMenuItem(menu)
    },
    // 根据菜单item跳转路由，并且维护tabList
    routeByMenuItem (menuItem) {
      // 在tabList已经存在该菜单
      let isExistMenuInTabList = this.tabList.findIndex(tab => tab.id == menuItem.id) != -1;
      // 在tabList不存在该菜单：往tabList push该菜单，激活tab选中效果，并切换路由
      if (!isExistMenuInTabList) {
        this.tabList.push(menuItem);
        // 该tab为新增的tab，保存在keepAlive缓存
        this.keepAliveComponennt.push(menuItem.routerName);
      }
      // 激活tab选中效果
      this.activeTabId = menuItem.id;
      // 切换路由
      if (menuItem.routerPath) {
        this.routeByPath(menuItem.routerPath)
      } else if (menuItem.routerName) {
        this.routeByName(menuItem.routerName)
      } else {
        console.error(`menuItem的routerName和routerPath不能全为空`)
        return;
      }
      //   // 该tab为新增的tab，保存在keepAlive缓存。使用setTimeout是因为$router.replace之后不能立刻获取最新的this.$route
      //   if (!isExistMenuInTabList) {
      //     setTimeout(() => {
      //     //   this.keepAliveComponennt.push(this.$route.name);
      //     }, 100)
      //   }
      // 更新面包屑
      this.breadcrumbList = menuItem.keyPath.map(key => {
        return this.leftMenu.find(item => item.id == key);
      })
      // 更新左侧菜单选中效果
      this.leftMenuActiveIndex = menuItem.id;
    },
    // 处理tab删除事件
    handleRemoveTab (targetTabId) {
      // 删除tab 并 激活旁边的tab
      let tabList = this.tabList;
      let activeTabId = this.activeTabId;
      if (activeTabId === targetTabId) {
        tabList.forEach((tab, index) => {
          if (tab.id === targetTabId) {
            let nextTab = tabList[index + 1] || tabList[index - 1];
            if (nextTab) {
              activeTabId = nextTab.id;
            }
          }
        });
      }
      this.tabList = tabList.filter(tab => tab.id !== targetTabId);
      this.activeTabId = activeTabId;

      // 删除keep-alive缓存
      let deletedMenu = this.leftMenu.find(item => item.id == targetTabId);
      this.keepAliveComponennt.splice(this.keepAliveComponennt.indexOf(deletedMenu.routerName), 1);

      // 跳转路由
      let menu = this.leftMenu.find(item => item.id == activeTabId);
      this.routeByMenuItem(menu);
    },
    handleClickTab (tab) {
      let targetMenuId = tab.name;
      // 获取tab对应的菜单路由
      let menu = this.leftMenu.find(item => item.id == targetMenuId);
      // 切换路由
      this.routeByMenuItem(menu);
    }
  }
}
</script>


<style>
html,
body {
  height: 100%;
  width: 100%;
}
/* 第一个tab不能删除 */
#centerTab .el-tabs__nav .el-tabs__item:nth-child(1) span {
  display: none;
}
</style>

<style lang="less" scoped>
#app {
  height: 100%;
  #appTopHeader {
    padding: 0px;
    display: flex;
    .el-menu {
      flex-grow: 0;
    }
  }
  #appLogo {
    width: 200px;
    display: flex;
    justify-content: center;
    img {
      max-height: 100%;
      max-width: 100%;
    }
  }
  #topNavMenu {
    width: calc(100% - 200px);
  }
}

// 左侧菜单导航栏
#leftNavMenu {
  height: 100%;
  ul {
    height: 97%;
    border-bottom: 1px solid #dcdfe6;
    overflow-x: hidden;
  }
}

#centerDiv {
  padding: 10px;
  // 面包屑
  #centerBreadcrumb {
    padding-bottom: 10px;
  }

  // 中间tab可视区域
  #centerTab {
    height: calc(100% - 30px);
  }
}
</style>>
